package com.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.domain.entity.Accessory;
import com.domain.entity.Assemble;
import com.domain.entity.Goods;
import com.domain.req.AddGoodsReq;
import com.domain.req.PageListReq;
import com.domain.req.PageReq;
import com.domain.req.UpdateGoodsReq;
import com.domain.vo.AccessoryPageListVO;
import com.domain.vo.GoodsGetByIdVO;
import com.exception.ServiceException;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.mapper.AccessoryMapper;
import com.mapper.AssembleMapper;
import com.mapper.GoodsMapper;
import com.service.GoodsService;
import com.utils.ValidatorUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author caishenao
 * @description 针对表【goods】的数据库操作Service实现
 * @createDate 2023-10-12 20:12:36
 */
@Service
@Slf4j
public class GoodsServiceImpl implements GoodsService {

    @Resource
    private GoodsMapper goodsMapper;

    @Resource
    private AccessoryMapper accessoryMapper;

    @Resource
    private AssembleMapper assembleMapper;

    /**
     * 根据id获取商品
     *
     * @param id 商品id
     * @return 商品信息
     */
    @Override
    public GoodsGetByIdVO getById(Integer id) {
        // 1. 查询商品信息
        log.info("getById的入参:{}", JSONObject.toJSONString(id));
        Goods goods = goodsMapper.getById(id);
        // 2. 判断商品信息是否存在
        if (goods == null) {
            // 商品信息不存在
            log.error("id为:{}的商品信息不存在!", JSONObject.toJSONString(id));
            throw new ServiceException("商品信息不存在!");
        }
        // 3. 查询商品的配件集合
        List<Assemble> assembleList = assembleMapper.listByGoodsId(goods.getId());
        List<Integer> accessoryIdList = assembleList.stream().map(Assemble::getAccessoryId).collect(Collectors.toList());

        // 4. 转换为对应的VO
        GoodsGetByIdVO goodsGetByIdVO = goodsGetByIdVOConversion(goods, accessoryIdList);
        log.info("getById的返参:{}", JSONObject.toJSONString(goodsGetByIdVO));
        return goodsGetByIdVO;
    }

    /**
     * 商品VO信息转换器
     *
     * @param goods           商品信息
     * @param accessoryIdList 商品的配件id集合
     * @return GoodsGetByIdVO
     */
    private GoodsGetByIdVO goodsGetByIdVOConversion(Goods goods, List<Integer> accessoryIdList) {
        GoodsGetByIdVO goodsGetByIdVO = new GoodsGetByIdVO();
        goodsGetByIdVO.setId(goods.getId());
        goodsGetByIdVO.setAssort(goods.getAssort());
        goodsGetByIdVO.setStock(goods.getStock());
        goodsGetByIdVO.setName(goods.getName());
        goodsGetByIdVO.setPicture(goods.getPicture());
        goodsGetByIdVO.setPrice(goods.getPrice());
        goodsGetByIdVO.setInputPrice(goods.getInputPrice());
        goodsGetByIdVO.setCreateTime(goods.getCreateTime());
        goodsGetByIdVO.setUpdateTime(goods.getUpdateTime());
        goodsGetByIdVO.setAccessoryIdList(accessoryIdList);

        return goodsGetByIdVO;
    }

    /**
     * 新增商品信息
     *
     * @param addGoodsReq 新增商品请求
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addGoods(AddGoodsReq addGoodsReq) {
        // 1. 数据校验
        ValidatorUtils.validateEntity(addGoodsReq);

        // 2. 查询配件信息
        List<Integer> accessoryIdList = addGoodsReq.getAccessoryIdList();
        List<AccessoryPageListVO> accessoryList = accessoryMapper.listByIdList(accessoryIdList);
        // 计算进价和售价
        Double inputPrice = 0D;
        Double price = 0D;
        // 遍历计算
        for (AccessoryPageListVO accessory : accessoryList) {
            inputPrice += accessory.getInputPrice();
            price += accessory.getSellPrice();
        }

        // 3. 封装商品对象
        Goods goods = addGoodsReqConversion(addGoodsReq, inputPrice, price);

        // 4. 新增商品信息
        goodsMapper.insertGoods(goods);

        // 5. 新增到组装表中
        accessoryIdList = accessoryList.stream().map(AccessoryPageListVO::getId).collect(Collectors.toList());
        List<Assemble> assembleList = assembleConversion(goods.getId(), accessoryIdList);
        for (Assemble assemble : assembleList) {
            // 遍历新增
            assembleMapper.insert(assemble);
        }
    }

    /**
     * 分页查询
     *
     * @param pageReq     分页请求
     * @param pageListReq 分页查询的内容
     * @return 商品的分页数据
     */
    @Override
    public PageInfo<Goods> pageList(PageReq pageReq, PageListReq pageListReq) {
        // 1. 开启分页
        PageHelper.startPage(pageReq.getPageNum(), pageReq.getPageSize());
        List<Goods> list = goodsMapper.listSelect(pageListReq);
        PageInfo<Goods> pageInfo = new PageInfo<>(list);
        return pageInfo;
    }

    /**
     * 根据商品id删除商品信息
     *
     * @param id 商品id
     */
    @Override
    public void deleteById(Integer id) {
        // 1. 判断商品信息是否存在
        Goods goods = goodsMapper.getById(id);
        if (goods == null) {
            log.error("要删除的商品不存在!");
            throw new ServiceException("要删除的商品不存在!");
        }

        // 2. 删除组装表中的数据
        List<Assemble> assembleList = assembleMapper.listByGoodsId(id);

        // 3. 删除组装数据
        for (Assemble assemble : assembleList) {
            assembleMapper.deleteById(assemble.getId());
        }

    }


    /**
     * 根据商品id修改商品信息
     *
     * @param updateGoodsReq 修改商品信息请求
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateById(UpdateGoodsReq updateGoodsReq) {
        // 1. 数据校验
        ValidatorUtils.validateEntity(updateGoodsReq);

        // 2. 判断商品信息是否存在
        Goods goods = goodsMapper.getById(updateGoodsReq.getId());
        if (goods == null) {
            // 商品信息不存在
            log.error("id为:{}的商品信息不存在,无法删除!", JSONObject.toJSONString(updateGoodsReq.getId()));
            throw new ServiceException("商品信息不存在,无法删除!");
        }

        // 3. 判断配件是否存在
        List<Integer> accessoryIdList = updateGoodsReq.getAccessoryIdList();
        List<AccessoryPageListVO> accessoryList = accessoryMapper.listByIdList(accessoryIdList);
        if (CollectionUtils.isEmpty(accessoryList)) {
            // 配件信息不存在
            log.error("配件信息不存在!");
            throw new ServiceException("配件信息不存在,无法更新!");
        }

        // 4. 重新补充组装数据
        // 先删除组装数据
        assembleMapper.deleteByGoodsId(updateGoodsReq.getId());
        // 再添加
        List<Assemble> assembleList = assembleConversion(goods.getId(), accessoryIdList);
        for (Assemble assemble : assembleList) {
            // 遍历新增
            assembleMapper.insert(assemble);
        }

        // 5. 修改商品数据
        Goods updated = updateGoodsReqConversion(updateGoodsReq);

        // 6. 修改数据库
        goodsMapper.updateGoods(updated);

        // 7. 重新计算
        recalculateByGoodsId(updateGoodsReq.getId());
    }

    /**
     * 根据商品id重新计算
     *
     * @param id 商品id
     */
    @Override
    @Transactional(propagation = Propagation.MANDATORY)
    public void recalculateByGoodsId(Integer id) {
        // 1. 商品是否存在
        Goods goods = goodsMapper.getById(id);
        if (goods == null) {
            // 商品信息为空
            log.error("商品信息为空，无法计算！");
            throw new ServiceException("商品信息为空，无法计算！");
        }

        // 2. 根据中间表查询查询所有配件
        List<Assemble> assembleList = assembleMapper.listByGoodsId(goods.getId());
        List<Integer> accessoryIdList = assembleList.stream().map(Assemble::getAccessoryId).collect(Collectors.toList());
        List<AccessoryPageListVO> accessoryList = accessoryMapper.listByIdList(accessoryIdList);
        // 计算进价和售价
        Double inputPrice = 0D;
        Double price = 0D;
        // 遍历计算
        for (AccessoryPageListVO accessory : accessoryList) {
            inputPrice += accessory.getInputPrice();
            price += accessory.getSellPrice();
        }
        goods.setInputPrice(inputPrice);
        goods.setPrice(price);

        // 3. 更新数据库
        goodsMapper.updateGoods(goods);
    }

    /**
     * 根据配件id重新计算商品的信息
     *
     * @param accessoryId 配件id
     */
    @Override
    @Transactional(propagation = Propagation.MANDATORY)
    public void recalculateByAccessoryId(Integer accessoryId, Double oldPrice, Double oldInputPrice) {
        // 1. 查询配件是否存在
        Accessory accessory = accessoryMapper.getById(accessoryId);
        if (accessory == null) {
            log.error("配件信息不存在");
            throw new ServiceException("配件信息不存在!");
        }

        // 2. 中间表查询组装配件的商品信息
        List<Assemble> assembleList = assembleMapper.listByAccessoryId(accessoryId);
        Set<Integer> goodsIdSet = assembleList.stream().map(Assemble::getGoodsId).collect(Collectors.toSet());
        List<Goods> goodsList = goodsMapper.listByIdList(goodsIdSet);

        // 3. 重新计算
        for (Goods goods : goodsList) {
            Double inputPrice = goods.getInputPrice();
            Double price = goods.getPrice();

            // 减去老的数据
            inputPrice -= oldInputPrice;
            price -= oldPrice;

            // 加上最新的数据
            inputPrice += accessory.getInputPrice();
            price += accessory.getSellPrice();

            Goods update = new Goods();
            update.setId(goods.getId());
            update.setInputPrice(inputPrice);
            update.setPrice(price);
            goodsMapper.updateGoods(goods);
        }

    }

    /**
     * 查询商品信息
     *
     * @param searchValue 输入的值
     * @return 符合查询条件的商品信息集合
     */
    @Override
    public List<Goods> selectGoods(String searchValue) {
        List<Goods> goodsList = goodsMapper.selectGoodsBySearchValue(searchValue);
        return goodsList;
    }

    /**
     * 根据商品id修改商品信息
     *
     * @param goods 商品信息
     */
    @Override
    public void update(Goods goods) {
        log.info("修改商品信息,入参:{}", JSONObject.toJSONString(goods));
        // 1. 根据商品id查询商品信息
        Goods byId = goodsMapper.getById(goods.getId());
        if (byId == null) {
            log.error("商品信息不存在!");
            throw new ServiceException("商品信息不存在!");
        }
        // 2. 更新商品信息
        goodsMapper.updateGoods(goods);
        log.info("商品信息更新完成!");
    }

    /**
     * 修改商品请求转换商品对象
     *
     * @param updateGoodsReq 修改商品请求
     * @return 转换后的商品信息
     */
    private Goods updateGoodsReqConversion(UpdateGoodsReq updateGoodsReq) {
        Goods goods = new Goods();
        goods.setId(updateGoodsReq.getId());
        goods.setAssort(updateGoodsReq.getAssort());
        goods.setStock(updateGoodsReq.getStock());
        goods.setName(updateGoodsReq.getName());
        goods.setPicture(updateGoodsReq.getPicture());
        goods.setUpdateTime(new Date());
        return goods;
    }

    /**
     * 商品id和配件id的转换器
     *
     * @param goodsId        商品id
     * @param accessorIdList 配件id集合
     * @return 组装表集合
     */
    private List<Assemble> assembleConversion(Integer goodsId, List<Integer> accessorIdList) {
        List<Assemble> assembleList = new ArrayList<>();
        for (Integer assembleId : accessorIdList) {
            Assemble assemble = new Assemble();
            assemble.setGoodsId(goodsId);
            assemble.setAccessoryId(assembleId);
            assembleList.add(assemble);
        }
        return assembleList;
    }

    /**
     * 新增商品请求转换为商品对象
     *
     * @param addGoodsReq 新增商品请求
     * @param inputPrice  进价
     * @param price       价格
     * @return 商品对象
     */
    private Goods addGoodsReqConversion(AddGoodsReq addGoodsReq, Double inputPrice, Double price) {
        Goods goods = new Goods();
        goods.setAssort(addGoodsReq.getAssort());
        goods.setStock(addGoodsReq.getStock());
        goods.setName(addGoodsReq.getName());
        goods.setPicture(addGoodsReq.getPicture());
        goods.setPrice(price);
        goods.setInputPrice(inputPrice);
        goods.setCreateTime(new Date());
        return goods;
    }
}




